package server.fassade;

import java.util.Collection;
import java.util.Map;
import javax.persistence.*;
import server.ejb.beans.*;

/**
 * Fassade as a collection of all method calls.
 */
@javax.ejb.Stateless
public final class Fassade implements IFassade {
	
	/* simulated sensors */
	private SimulatedSensors sensors = new SimulatedSensors(this);
	
	/**
	 * EntityManager for Everything.
	 */
	@PersistenceContext (unitName = "Flughafen")
	private EntityManager emFlughafen;

	/**
	 * Dirty flag.
	 */
	private boolean isDirty;
	
	@Override
	public int createAngestellter(String name, String vorname) {
		Angestellter a = new Angestellter();
		a.setNachname(name);
		a.setVorname(vorname);
		emFlughafen.persist(a);
		return a.getmNr();
	}

	/**
	 * Create new Buchung.
	 */
	@Override
	public int createBuchung(int FlugzeugID) {
		Flugzeug f = emFlughafen.find(Flugzeug.class, FlugzeugID);
		Buchung b = new Buchung();
		b.setFlugzeug(f);
		Konto k = emFlughafen.find(Konto.class, f.getFluggesellschaft().getKonto().getKtoNr());
		k.addBuchung(b);
		emFlughafen.persist(b);
		emFlughafen.merge(k);
		return b.getBuchNr();
	}

	/**
	 * create a flight corporation
	 */
	@Override
	public int createFluggesellschaft (String bezeichnung) {
		isDirty = true;
		Fluggesellschaft fg = new Fluggesellschaft();
		Konto k = new Konto();
		emFlughafen.persist(k);
		
		fg.setBezeichnung(bezeichnung);
		fg.setKonto(k);
		emFlughafen.persist(fg);
		return fg.getID ();
	}

	/**
	 * create an aircraft.
	 */
	@Override
	public int createFlugzeug (String bezeichnung, int FluggesellschaftID, int FlugzeugtypID) {
		isDirty = true;
		Flugzeug fzg = new Flugzeug();
		Flugzeugtyp ft = emFlughafen.find (Flugzeugtyp.class, FlugzeugtypID);
		Fluggesellschaft fg = emFlughafen.find (Fluggesellschaft.class, FluggesellschaftID);
		fg.addFlugzeug(fzg);
		emFlughafen.persist(fg);

		fzg.setBezeichnung(bezeichnung);
		fzg.setFluggesellschaft(fg);
		fzg.setFlugzeugtyp(ft);
		emFlughafen.persist(fzg);
		return fzg.getID();
	}

	/**
	 * create an aircraft type.
	 */
	@Override
	public int createFlugzeugtyp (String bezeichnung, int gebuehr) {
		isDirty = true;
		Flugzeugtyp ft = new Flugzeugtyp();
		Gebuehr g = new Gebuehr();
		g.setGebuehrHoehe(gebuehr);
		emFlughafen.merge(g);
		
		ft.setBezeichnung(bezeichnung);
		ft.setGebuehr(g);
		emFlughafen.persist(ft);
		return ft.getID();
	}

	/**
	 * Create Lotse.
	 */
	public int createLotse(String name, String vorname) {
		isDirty = true;
		Lotse l = new Lotse();
		l.setNachname(name);
		l.setVorname(vorname);
		emFlughafen.persist(l);
		return l.getmNr();
	}

	/**
	 * create a parking position
	 */
	@Override
	public int createParkposition (String bezeichnung) {
		isDirty = true;
		Parkposition pp = new Parkposition ();
		/* initialize pseudo sensor as empty parking position */
		this.sensors.getPseudoLandingLaneSensors().put(pp.getID(), false);
		pp.setBezeichnung (bezeichnung);
		emFlughafen.persist(pp);
		return pp.getID ();
	}

	/**
	 * create a landing lane
	 */
	@Override
	public int createStartLandebahn (String bezeichnung) {
		isDirty = true;
		StartLandebahn lb = new StartLandebahn ();
		/* initialize pseudo sensor as empty landing lane */
		this.sensors.getPseudoLandingLaneSensors().put(lb.getID(),false);
		lb.setBezeichnung (bezeichnung);
		emFlughafen.persist(lb);
		return lb.getID ();
	}
	
	/**
	 * Get Angestellter by mNr.
	 */
	@Override
	public Angestellter getAngestellter(int mNr) {
		Angestellter a = (Angestellter)emFlughafen.find(Angestellter.class, mNr);
		return a;
	}

	/**
	 * Get Buchung by ID.
	 */
	@Override
	public Buchung getBuchung(int ID) {
		Buchung b = (Buchung)emFlughafen.find(Buchung.class, ID);
		return b;
	}

	/**
	 * get a flight corporation by ID
	 */
	@Override
	public Fluggesellschaft getFluggesellschaft (int ID) {
		Fluggesellschaft fg = emFlughafen.find (Fluggesellschaft.class, ID);
		return fg;
	}

	/**
	 * get an aircraft by ID
	 */
	@Override
	public Flugzeug getFlugzeug (int ID) {
		Flugzeug entity = emFlughafen.find (Flugzeug.class, ID);
		return entity;
	}

	/**
	 * get an aircraft type by ID
	 */
	@Override
	public Flugzeugtyp getFlugzeugtyp (int ID) {
		Flugzeugtyp ft = emFlughafen.find (Flugzeugtyp.class, ID);
		return ft;
	}
	
	/**
	 * Get Gebuehr by gebID.
	 */
	@Override
	public Gebuehr getGebuehr(int gebID) {
		Gebuehr g = emFlughafen.find(Gebuehr.class, gebID);
		return g;
	}

	/**
	 * Get Konto by KtoNr.
	 */
	@Override
	public Konto getKonto(int ktoNr) {
		Konto k = emFlughafen.find(Konto.class, ktoNr);
		return k;
	}
	
	/**
	 * Get Lotse by mNr.
	 */
	@Override
	public Lotse getLotse(int mNr) {
		Lotse l = emFlughafen.find(Lotse.class, mNr);
		return l;
	}

	/**
	 * get a parking position by ID
	 */
	@Override
	public Parkposition getParkposition(int ID) {
		Parkposition pp = emFlughafen.find (Parkposition.class, ID);
		return pp;
	}
	
	/**
	 * Get Schichtplan by sNr.
	 */
	@Override
	public Schichtplan getSchichtplan(int sNr) {
		Schichtplan sp = emFlughafen.find(Schichtplan.class, sNr);
		return sp;
	}

	/**
	 * get a landing lane by ID
	 */
	@Override
	public StartLandebahn getStartLandebahn (int ID) {
		StartLandebahn lb = emFlughafen.find(StartLandebahn.class, ID);
		return lb;
	}
	
	/**
	 * Get Urlaubsplan by urlNr.
	 */
	@Override
	public Urlaubsplan getUrlaubsplan(int urlNr) {
		Urlaubsplan url = emFlughafen.find(Urlaubsplan.class, urlNr);
		return url;
	}

	/**
	 * Get all Angestellter.
	 */
	@Override
	public Collection<Angestellter> getAngestellter() {
		Query q = emFlughafen.createQuery("SELECT e FROM Angestellter e ORDER BY e.nachname, e.vorname");
		@SuppressWarnings("unchecked")
		Collection<Angestellter> col = q.getResultList();
		return col;
	}

	/**
	 * Get all Buchung.
	 */
	@Override
	public Collection<Buchung> getBuchung() {
		Query q = emFlughafen.createQuery("SELECT e FROM Buchung e ORDER BY e.datum");
		@SuppressWarnings("unchecked")
		Collection<Buchung> col = q.getResultList();
		return col;
	}

	/**
	 * get a list of all flight corporations
	 */
	@Override
	public Collection<Fluggesellschaft> getFluggesellschaft() {
		Query q = emFlughafen.createQuery("SELECT e FROM Fluggesellschaft e ORDER BY e.bezeichnung");
		@SuppressWarnings("unchecked")
		Collection<Fluggesellschaft> col = q.getResultList();
		return col;
	}

	/**
	 * get a list of all aircrafts
	 */
	@Override
	public Collection<Flugzeug> getFlugzeug() {
		Query q = emFlughafen.createQuery("SELECT e FROM Flugzeug e ORDER BY e.bezeichnung");
		@SuppressWarnings("unchecked")
		Collection<Flugzeug> col = q.getResultList();
		return col;
	}

	/**
	 * get a list of all aircraft types
	 */
	@Override
	public Collection<Flugzeugtyp> getFlugzeugtyp() {
		Query q = emFlughafen.createQuery("SELECT e FROM Flugzeugtyp e ORDER BY e.bezeichnung");
		@SuppressWarnings("unchecked")
		Collection<Flugzeugtyp> col = q.getResultList();
		return col;
	}

	/**
	 * Get all Gebuehr entries.
	 */
	@Override
	public Collection<Gebuehr> getGebuehr() {
		Query q = emFlughafen.createQuery("SELECT e FROM Gebuehr e ORDER BY e.gebuehrHoehe");
		@SuppressWarnings("unchecked")
		Collection<Gebuehr> col = q.getResultList();
		return col;
	}

	/**
	 * Get all Konto.
	 */
	@Override
	public Collection<Konto> getKonto() {
		Query q = emFlughafen.createQuery("SELECT e FROM Konto e ORDER BY e.ktoNr");
		@SuppressWarnings("unchecked")
		Collection<Konto> col = q.getResultList();
		return col;
	}

	/**
	 * Get all Lotse.
	 */
	@Override
	public Collection<Lotse> getLotse() {
		Query q = emFlughafen.createQuery("SELECT e FROM Lotse e ORDER BY e.nachname, e.vorname");
		@SuppressWarnings("unchecked")
		Collection<Lotse> col = q.getResultList();
		return col;
	}

	/**
	 * get a list of all parking positions
	 */
	@Override
	public Collection<Parkposition> getParkposition() {
		Query q = emFlughafen.createQuery("SELECT e FROM Parkposition e ORDER BY e.bezeichnung");
		@SuppressWarnings("unchecked")
		Collection<Parkposition> col = q.getResultList();
		return col;
	}

	/**
	 * Get all Schichtplan.
	 */
	@Override
	public Collection<Schichtplan> getSchichtplan() {
		Query q = emFlughafen.createQuery("SELECT e FROM Schichtplan e");
		@SuppressWarnings("unchecked")
		Collection<Schichtplan> col = q.getResultList();
		return col;
	}

	/**
	 * Get all Rollbahnen.
	 */
	@Override
	public Collection<StartLandebahn> getStartLandebahn() {
		Query q = emFlughafen.createQuery("SELECT e FROM StartLandebahn e ORDER BY e.ID");
		@SuppressWarnings("unchecked")
		Collection<StartLandebahn> col = q.getResultList();
		return col;
	}

	/**
	 * Get all Urlaubsplan.
	 */
	@Override
	public Collection<Urlaubsplan> getUrlaubsplan() {
		Query q = emFlughafen.createQuery("SELECT e FROM Urlaubsplan e");
		@SuppressWarnings("unchecked")
		Collection<Urlaubsplan> col = q.getResultList();
		return col;
	}

	/**
	 * update an aircraft with a new name
	 */
	@Override
	public void updateFlugzeug (int ID, String bezeichnung) {
		isDirty = true;
		Flugzeug entity = emFlughafen.find (Flugzeug.class, ID);
		entity.setBezeichnung (bezeichnung);
		emFlughafen.persist (entity);
	}

	/**
	 * update a flight corporation with a new name
	 */
	@Override
	public void updateFluggesellschaft (int ID, String bezeichnung) {
		isDirty = true;
		Fluggesellschaft entity = emFlughafen.find (Fluggesellschaft.class, ID);
		entity.setBezeichnung (bezeichnung);
		emFlughafen.persist (entity);
	}

	/**
	 * update an aircraft type with a new name
	 */
	@Override
	public void updateFlugzeugtyp (int ID, String bezeichnung) {
		isDirty = true;
		Flugzeugtyp entity = emFlughafen.find (Flugzeugtyp.class, ID);
		entity.setBezeichnung (bezeichnung);
		emFlughafen.persist (entity);
	}

	/**
	 * update a landing lane with a new name
	 */
	@Override
	public void updateStartLandebahn (int ID, String bezeichnung) {
		isDirty = true;
		StartLandebahn entity = emFlughafen.find (StartLandebahn.class, ID);
		entity.setBezeichnung (bezeichnung);
		emFlughafen.persist (entity);
	}

	/**
	 * update a parking position with a new name
	 */
	@Override
	public void updateParkposition (int ID, String bezeichnung) {
		isDirty = true;
		Parkposition entity = emFlughafen.find (Parkposition.class, ID);
		entity.setBezeichnung (bezeichnung);
		emFlughafen.persist (entity);
	}

	/**
	 * get an aircraft by a search string
	 */
	@Override
	public Collection<Flugzeug> getFlugzeug(String bezeichnung) {
		Query query = emFlughafen.createQuery ("SELECT e FROM Flugzeug e WHERE e.bezeichnung='" + bezeichnung + "'"); 
		@SuppressWarnings("unchecked")
		Collection<Flugzeug> col = query.getResultList();
		return col;
	}

	/**
	 * get an aircraft type by a search string
	 */
	@Override
	public Collection<Flugzeugtyp> getFlugzeugtyp(String bezeichnung) {
		Query query = emFlughafen.createQuery ("SELECT e FROM Flugzeugtyp e WHERE e.bezeichnung='" + bezeichnung + "'"); 
		@SuppressWarnings("unchecked")
		Collection<Flugzeugtyp> col = query.getResultList();
		return col;
	}

	/**
	 * get a flight corporation by a search string
	 */
	@Override
	public Collection<Fluggesellschaft> getFluggesellschaft(String bezeichnung) {
		Query query = emFlughafen.createQuery ("select e from Fluggesellschaft e WHERE e.bezeichnung='" + bezeichnung + "'"); 
		@SuppressWarnings("unchecked")
		Collection<Fluggesellschaft> col = query.getResultList();
		return col;
	}

	/**
	 * remove an aircraft with a specified ID
	 */
	@Override
	public void removeFlugzeug (int ID) {
		isDirty = true;
		Flugzeug entity = emFlughafen.find (Flugzeug.class, ID);
		if (entity != null) {
			emFlughafen.remove (entity);
		}
	}

	/**
	 * remove an aircraft type with a specified ID
	 */
	@Override
	public void removeFlugzeugtyp (int ID) {
		isDirty = true;
		Flugzeugtyp entity = emFlughafen.find (Flugzeugtyp.class, ID);
		if (entity != null) {
			emFlughafen.remove (entity);
		}
	}

	/**
	 * remove a flight corporation with a specified ID
	 */
	@Override
	public void removeFluggesellschaft (int ID) {
		isDirty = true;
		Fluggesellschaft entity = emFlughafen.find (Fluggesellschaft.class, ID);
		if (entity != null) {
			emFlughafen.remove (entity);
		}
	}

	/**
	 * remove a parking position with a specified ID
	 */
	@Override
	public void removeParkposition (int ID) {
		isDirty = true;
		Parkposition entity = emFlughafen.find (Parkposition.class, ID);
		if (entity != null) {
			emFlughafen.remove (entity);
		}
		if (this.sensors.getPseudoParkingPositionSensors().containsKey(entity.getID())){
			this.sensors.getPseudoParkingPositionSensors().remove(entity.getID());
		}
	}

	/**
	 * remove a landing lane with a specified ID
	 */
	@Override
	public void removeStartLandebahn (int ID) {
		isDirty = true;
		StartLandebahn entity = emFlughafen.find (StartLandebahn.class, ID);
		if (entity != null) {
			emFlughafen.remove (entity);
		}
		if (this.sensors.getPseudoLandingLaneSensors().containsKey(entity.getID())){
			this.sensors.getPseudoLandingLaneSensors().remove(entity.getID());
		}
	}

	/**
	 * Remove Konto by ktoNr.
	 */
	@Override
	public void removeKonto(int ktoNr) {
		Konto k = emFlughafen.find(Konto.class, ktoNr);
		if (k != null) {
			emFlughafen.remove(k);
		}
	}

	/**
	 * set the time when an aircraft is expected to land
	 */
	@Override
	public void setSollzeitLandung(int flugzeugID, String zeit) {
		Flugzeug entity = emFlughafen.find (Flugzeug.class, flugzeugID);
		entity.setSollzeitLandung (zeit);
		emFlughafen.persist (entity);
	}

	/**
	 * contract a parking position out to an aircraft
	 */
	@Override
	public void setParkpositionOcc(int flugzeugID, int parkpositionID) {
		isDirty = true;
		Flugzeug fzg = emFlughafen.find (Flugzeug.class, flugzeugID);
		Parkposition pp = emFlughafen.find (Parkposition.class, parkpositionID);
		pp.setFree(false);
		fzg.setParkposition(pp);
		emFlughafen.persist (fzg);
	}
	
	/**
	 * remove contract between parking position and aircraft
	 */
	@Override
	public void setParkpositionFree(int flugzeugID, int parkpositionID) {
		isDirty = true;
		Flugzeug fzg = emFlughafen.find (Flugzeug.class, flugzeugID);
		Parkposition pp = emFlughafen.find (Parkposition.class, parkpositionID);
		pp.setFree(true);
		//fzg.setParkposition(null);
		emFlughafen.persist (fzg);
	}

	/**
	 * contract a landing lane out to an aircraft
	 */
	@Override
	public void setStartLandebahnOcc(int flugzeugID, int StartLandebahnID) {
		isDirty = true;
		Flugzeug fzg = emFlughafen.find (Flugzeug.class, flugzeugID);
		StartLandebahn lb = emFlughafen.find (StartLandebahn.class, flugzeugID);
		lb.setFree(false);
		fzg.setStartLandebahn(lb);				
		emFlughafen.persist (fzg);
	}

	/**
	 * release a landing lane
	 */
	@Override
	public void setStartLandebahnFree(int flugzeugID) {
		isDirty = true;
		Flugzeug entity = emFlughafen.find (Flugzeug.class, flugzeugID);
		entity.setStartLandebahnFreigabe (true);
		emFlughafen.persist (entity);
	}

	/**
	 * set a landing completed with the time when the aircraft landed
	 */
	@Override
	public void setIstzeitLandung(int flugzeugID, String istZeit) {
		isDirty = true;
		Flugzeug entity = emFlughafen.find (Flugzeug.class, flugzeugID);
		entity.setIstzeitLandung (istZeit);
		emFlughafen.persist (entity);
	}

	/**
	 * Update Kontostand.
	 */
	@Override
	public void updateKonto(int ktoNr, int stand) {
		Konto k = emFlughafen.find(Konto.class, ktoNr);
		k.setBalance(stand);
		emFlughafen.persist(k);
	}

	@Override
	public void startEinplanen(int startId, int fluggesellschaftId,
			int flugzeugId, String sollzeit) {
		isDirty = true;			
		StartLandebahn startbahn = emFlughafen.find(StartLandebahn.class, startId);
		Flugzeug f = emFlughafen.find(Flugzeug.class, flugzeugId);
		/* set pseudo sensor values to true (cannot be given free yet) */
		this.sensors.getPseudoParkingPositionSensors().put(f.getParkposition().getID(), true);					 
		this.sensors.getPseudoLandingLaneSensors().put(startId, true);
		
		f.setSollzeitLandung(sollzeit);
		f.setStartLandebahn(startbahn);
		startbahn.setFree(false);
		emFlughafen.persist(f);
		emFlughafen.persist(startbahn);
		//f.setStartLandebahnFreigabe(value); ???
		
		/* start new sensor thread for simulated sensors */
		SimulatedSensors sensorsThread = new SimulatedSensors(this);
		sensorsThread.setValues(f.getParkposition().getID(), startId);
		//System.out.println("Pre Thread");
		sensorsThread.start();
		//System.out.println("Post Thread");
		 
	}
	
	@Override
	public void startBahnBelegungAndern(int startId, boolean isBahnFree) {
		isDirty = true;
		StartLandebahn startbahn = emFlughafen.find(StartLandebahn.class, startId);
		startbahn.setFree(isBahnFree);
	}

	@Override
	public boolean isDirty() {
		boolean temp = isDirty;
		isDirty = false;
		return temp;
	}

	/* setter so the sensors can access the flag */
	protected void setIsDirty(boolean b){	
		this.isDirty |= b;
	}
	
	@Override
	public Map<Integer,Boolean> getParkingPositionSensors(){
		return this.sensors.getPseudoParkingPositionSensors();
	}
	
	@Override
	public Map<Integer,Boolean> getLandingLaneSensors(){
		return this.sensors.getPseudoLandingLaneSensors();
	}
	
	/**
	 * This method wraps up the start process (mainly creates the 'Buchung')
	 * @param flugzeugId ID of the plane that just started
	 */
	public void finishStartProcess(int flugzeugId){
		this.createBuchung(flugzeugId);
	}
}